package moe.oil.db.service;

import lombok.Setter;
import moe.oil.api.emailAPI.EmailAPI;
import moe.oil.db.entity.Session;
import moe.oil.db.entity.User;
import moe.oil.db.repo.UserRepo;
import moe.oil.dto.user.UserDTO;
import moe.oil.exception.email.EmailExistException;
import moe.oil.exception.user.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Optional;


// TODO: 2022/4/16  修改抛出的异常为自定义类型，进行更好的控制

@Service
@Setter(onMethod_ = @Autowired)
public class UserService implements BaseService {
    public UserRepo userRepo;
    public PasswordEncoder passwordEncoder;
    public SessionService sessionService;

    public EmailAPI emailAPI;

    public Optional<UserDTO> selectUserByUsername(String username) {
        Optional<User> user = userRepo.findByUsername(username);
        return user.map(User::convert).or(() -> Optional.of(new UserDTO()));
    }

    /**
     * 根据ID查询用户
     *
     * @param id: 用户ID
     * @return: 用户信息
     */
    public Optional<UserDTO> selectUserById(Long id) {
        return Optional.of(
                (userRepo.findById(id).
                        orElseThrow(() ->
                                new RuntimeException("user not found"))).convert());
    }

    /**
     * 根据email查询用户
     *
     * @param email: 用户email
     * @return: 用户信息
     */
    public Optional<UserDTO> selectUserByEmail(String email) {
        Optional<User> user = userRepo.findByEmail(email);
        return Optional
                .of(user.map(User::convert)
                        .orElseThrow(() -> new EmailNotFoundException(email)));
    }

    /**
     * 验证账号密码
     *
     * @param username: 用户名
     * @param password: 密码
     * @return: 用户信息
     */

    public boolean canLogin(String username, String password) {
        var d = userRepo
                .findByUsername(username);
        return d.filter(user -> passwordEncoder.matches(password, user.getPassword())).isPresent();
    }

    /**
     * 添加数据
     *
     * @param userDTO: 用户信息
     * @return: 添加结果
     */
    //注意 ： ! 密码需要加密 再保存！
    public Optional<UserDTO> insertUser(UserDTO userDTO) {
        return Optional.of(
                userRepo
                        .save(new User(userDTO
                                .setSchoolDTO(null)))
                        .convert()
        );
    }

    /**
     * 根据ID删除用户信息
     *
     * @param id 用户ID
     * @return int
     */
    public int deleteUser(Long id) {
        var deleted = userRepo.deleteByUserId(id);
        if (deleted == 0) {
            throw new UserIdNotFoundException(id);
        }
        return deleted;
    }

    /**
     * 登陆成功后，   更新session
     */

    // TODO: 2022/4/15 session验证
    public Optional<UserDTO> login(UserDTO userDTO) {
        if (!canLogin(userDTO.getUsername(), userDTO.getPassword())) {
            throw new UserLoginErrorException(userDTO, userDTO.getUsername());
        }


        var user = userRepo.findByUsername(userDTO.getUsername()).orElseThrow(() -> new UsernameNotFoundException(userDTO.getUsername()));
        var session =
                sessionService.createSession(user.getUserId(), user.getUsername())
                        .orElseThrow();

        session.setToken(session.getToken())
                .setCreateTime(session.getCreateTime())
                .setExpireTime(session.getExpireTime())
                .setSessionId(user.getSession() != null ? user.getSession().getSessionId() : null);

        user.setSession(new Session(session));

        userRepo.save(user);//update session

        return Optional.of(user.convert().setPassword(""));
    }


    /**
     * 获取全部用户信息
     */
    public List<UserDTO> findAllUser(int page, int size) {
        return userRepo.findAll(PageRequest.of(page, size)).stream().map(User::convert).collect(java.util.stream.Collectors.toList());
    }

    /**
     * 查询email是否存在
     */
    public boolean isEmailExist(String email) {
        return userRepo.findByEmail(email).isPresent();
    }

    /**
     * 查询用户名是否存在
     */

    public boolean isUsernameExist(@NotNull(message = "email 不能为空") @NotBlank(message = "email 不能为空") String username) {
        return userRepo.findByUsername(username).isPresent();
    }

    //使用 email 发送邮件
    public void register(UserDTO userDTO) {
        if (isUsernameExist(userDTO.getUsername())) {
            throw new UsernameExistException(userDTO.getUsername());
        }
        if (isEmailExist(userDTO.getEmail())) {
            throw new EmailExistException(userDTO.getEmail());
        }

        String encodePassword = passwordEncoder.encode(userDTO.getPassword());
        emailAPI.send(userDTO.setPassword(encodePassword));
    }

    public String testEmail(String value) {
        return emailAPI.test(value);
    }
}
